home *** CD-ROM | disk | FTP | other *** search
/ PC/CD Gamer UK 120 / CD Gamer Issue 120 (March 2003) (Disc 2).ISO / mods / Q2_Codered / codeRED1_0.exe / Data1.cab / keys.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-13  |  18.5 KB  |  945 lines

  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. #include "client.h"
  21.  
  22. /*
  23.  
  24. key up events are sent even if in console mode
  25.  
  26. */
  27.  
  28.  
  29. #define        MAXCMDLINE    256
  30. char    key_lines[32][MAXCMDLINE];
  31. int        key_linepos;
  32. int        shift_down=false;
  33. int    anykeydown;
  34.  
  35. int        edit_line=0;
  36. int        history_line=0;
  37.  
  38. int        key_waiting;
  39. char    *keybindings[256];
  40. qboolean    consolekeys[256];    // if true, can't be rebound while in console
  41. qboolean    menubound[256];    // if true, can't be rebound while in menu
  42. int        keyshift[256];        // key to map to if shift held down in console
  43. int        key_repeats[256];    // if > 1, it is autorepeating
  44. qboolean    keydown[256];
  45.  
  46. typedef struct
  47. {
  48.     char    *name;
  49.     int        keynum;
  50. } keyname_t;
  51.  
  52. keyname_t keynames[] =
  53. {
  54.     {"TAB", K_TAB},
  55.     {"ENTER", K_ENTER},
  56.     {"ESCAPE", K_ESCAPE},
  57.     {"SPACE", K_SPACE},
  58.     {"BACKSPACE", K_BACKSPACE},
  59.     {"UPARROW", K_UPARROW},
  60.     {"DOWNARROW", K_DOWNARROW},
  61.     {"LEFTARROW", K_LEFTARROW},
  62.     {"RIGHTARROW", K_RIGHTARROW},
  63.  
  64.     {"ALT", K_ALT},
  65.     {"CTRL", K_CTRL},
  66.     {"SHIFT", K_SHIFT},
  67.     
  68.     {"F1", K_F1},
  69.     {"F2", K_F2},
  70.     {"F3", K_F3},
  71.     {"F4", K_F4},
  72.     {"F5", K_F5},
  73.     {"F6", K_F6},
  74.     {"F7", K_F7},
  75.     {"F8", K_F8},
  76.     {"F9", K_F9},
  77.     {"F10", K_F10},
  78.     {"F11", K_F11},
  79.     {"F12", K_F12},
  80.  
  81.     {"INS", K_INS},
  82.     {"DEL", K_DEL},
  83.     {"PGDN", K_PGDN},
  84.     {"PGUP", K_PGUP},
  85.     {"HOME", K_HOME},
  86.     {"END", K_END},
  87.  
  88.     {"MOUSE1", K_MOUSE1},
  89.     {"MOUSE2", K_MOUSE2},
  90.     {"MOUSE3", K_MOUSE3},
  91.  
  92.     {"JOY1", K_JOY1},
  93.     {"JOY2", K_JOY2},
  94.     {"JOY3", K_JOY3},
  95.     {"JOY4", K_JOY4},
  96.  
  97.     {"AUX1", K_AUX1},
  98.     {"AUX2", K_AUX2},
  99.     {"AUX3", K_AUX3},
  100.     {"AUX4", K_AUX4},
  101.     {"AUX5", K_AUX5},
  102.     {"AUX6", K_AUX6},
  103.     {"AUX7", K_AUX7},
  104.     {"AUX8", K_AUX8},
  105.     {"AUX9", K_AUX9},
  106.     {"AUX10", K_AUX10},
  107.     {"AUX11", K_AUX11},
  108.     {"AUX12", K_AUX12},
  109.     {"AUX13", K_AUX13},
  110.     {"AUX14", K_AUX14},
  111.     {"AUX15", K_AUX15},
  112.     {"AUX16", K_AUX16},
  113.     {"AUX17", K_AUX17},
  114.     {"AUX18", K_AUX18},
  115.     {"AUX19", K_AUX19},
  116.     {"AUX20", K_AUX20},
  117.     {"AUX21", K_AUX21},
  118.     {"AUX22", K_AUX22},
  119.     {"AUX23", K_AUX23},
  120.     {"AUX24", K_AUX24},
  121.     {"AUX25", K_AUX25},
  122.     {"AUX26", K_AUX26},
  123.     {"AUX27", K_AUX27},
  124.     {"AUX28", K_AUX28},
  125.     {"AUX29", K_AUX29},
  126.     {"AUX30", K_AUX30},
  127.     {"AUX31", K_AUX31},
  128.     {"AUX32", K_AUX32},
  129.  
  130.     {"KP_HOME",            K_KP_HOME },
  131.     {"KP_UPARROW",        K_KP_UPARROW },
  132.     {"KP_PGUP",            K_KP_PGUP },
  133.     {"KP_LEFTARROW",    K_KP_LEFTARROW },
  134.     {"KP_5",            K_KP_5 },
  135.     {"KP_RIGHTARROW",    K_KP_RIGHTARROW },
  136.     {"KP_END",            K_KP_END },
  137.     {"KP_DOWNARROW",    K_KP_DOWNARROW },
  138.     {"KP_PGDN",            K_KP_PGDN },
  139.     {"KP_ENTER",        K_KP_ENTER },
  140.     {"KP_INS",            K_KP_INS },
  141.     {"KP_DEL",            K_KP_DEL },
  142.     {"KP_SLASH",        K_KP_SLASH },
  143.     {"KP_MINUS",        K_KP_MINUS },
  144.     {"KP_PLUS",            K_KP_PLUS },
  145.  
  146.     {"MWHEELUP", K_MWHEELUP },
  147.     {"MWHEELDOWN", K_MWHEELDOWN },
  148.  
  149.     {"PAUSE", K_PAUSE},
  150.  
  151.     {"SEMICOLON", ';'},    // because a raw semicolon seperates commands
  152.  
  153.     {NULL,0}
  154. };
  155.  
  156. /*
  157. ==============================================================================
  158.  
  159.             LINE TYPING INTO THE CONSOLE
  160.  
  161. ==============================================================================
  162. */
  163.  
  164. void CompleteCommand (void)
  165. {
  166.     char    *cmd, *s;
  167.  
  168.     s = key_lines[edit_line]+1;
  169.     if (*s == '\\' || *s == '/')
  170.         s++;
  171.  
  172.     cmd = Cmd_CompleteCommand (s);
  173.     if (!cmd)
  174.         cmd = Cvar_CompleteVariable (s);
  175.     if (cmd)
  176.     {
  177.         key_lines[edit_line][1] = '/';
  178.         strcpy (key_lines[edit_line]+2, cmd);
  179.         key_linepos = strlen(cmd)+2;
  180.         key_lines[edit_line][key_linepos] = ' ';
  181.         key_linepos++;
  182.         key_lines[edit_line][key_linepos] = 0;
  183.         return;
  184.     }
  185. }
  186.  
  187. /*
  188. ====================
  189. Key_Console
  190.  
  191. Interactive line editing and console scrollback
  192. ====================
  193. */
  194. void Key_Console (int key)
  195. {
  196.  
  197.     switch ( key )
  198.     {
  199.     case K_KP_SLASH:
  200.         key = '/';
  201.         break;
  202.     case K_KP_MINUS:
  203.         key = '-';
  204.         break;
  205.     case K_KP_PLUS:
  206.         key = '+';
  207.         break;
  208.     case K_KP_HOME:
  209.         key = '7';
  210.         break;
  211.     case K_KP_UPARROW:
  212.         key = '8';
  213.         break;
  214.     case K_KP_PGUP:
  215.         key = '9';
  216.         break;
  217.     case K_KP_LEFTARROW:
  218.         key = '4';
  219.         break;
  220.     case K_KP_5:
  221.         key = '5';
  222.         break;
  223.     case K_KP_RIGHTARROW:
  224.         key = '6';
  225.         break;
  226.     case K_KP_END:
  227.         key = '1';
  228.         break;
  229.     case K_KP_DOWNARROW:
  230.         key = '2';
  231.         break;
  232.     case K_KP_PGDN:
  233.         key = '3';
  234.         break;
  235.     case K_KP_INS:
  236.         key = '0';
  237.         break;
  238.     case K_KP_DEL:
  239.         key = '.';
  240.         break;
  241.     }
  242.  
  243.     if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) ||
  244.          ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) )
  245.     {
  246.         char *cbd;
  247.         
  248.         if ( ( cbd = Sys_GetClipboardData() ) != 0 )
  249.         {
  250.             int i;
  251.  
  252.             strtok( cbd, "\n\r\b" );
  253.  
  254.             i = strlen( cbd );
  255.             if ( i + key_linepos >= MAXCMDLINE)
  256.                 i= MAXCMDLINE - key_linepos;
  257.  
  258.             if ( i > 0 )
  259.             {
  260.                 cbd[i]=0;
  261.                 strcat( key_lines[edit_line], cbd );
  262.                 key_linepos += i;
  263.             }
  264.             free( cbd );
  265.         }
  266.  
  267.         return;
  268.     }
  269.  
  270.     if ( key == 'l' ) 
  271.     {
  272.         if ( keydown[K_CTRL] )
  273.         {
  274.             Cbuf_AddText ("clear\n");
  275.             return;
  276.         }
  277.     }
  278.  
  279.     if ( key == K_ENTER || key == K_KP_ENTER )
  280.     {    // backslash text are commands, else chat
  281.         if (key_lines[edit_line][1] == '\\' || key_lines[edit_line][1] == '/')
  282.             Cbuf_AddText (key_lines[edit_line]+2);    // skip the >
  283.         else
  284.             Cbuf_AddText (key_lines[edit_line]+1);    // valid command
  285.  
  286.         Cbuf_AddText ("\n");
  287.         Com_Printf ("%s\n",key_lines[edit_line]);
  288.         edit_line = (edit_line + 1) & 31;
  289.         history_line = edit_line;
  290.         key_lines[edit_line][0] = ']';
  291.         key_linepos = 1;
  292.         if (cls.state == ca_disconnected)
  293.             SCR_UpdateScreen ();    // force an update, because the command
  294.                                     // may take some time
  295.         return;
  296.     }
  297.  
  298.     if (key == K_TAB)
  299.     {    // command completion
  300.         CompleteCommand ();
  301.         return;
  302.     }
  303.     
  304.     if ( ( key == K_BACKSPACE ) || ( key == K_LEFTARROW ) || ( key == K_KP_LEFTARROW ) || ( ( key == 'h' ) && ( keydown[K_CTRL] ) ) )
  305.     {
  306.         if (key_linepos > 1)
  307.             key_linepos--;
  308.         return;
  309.     }
  310.  
  311.     if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ||
  312.          ( ( key == 'p' ) && keydown[K_CTRL] ) )
  313.     {
  314.         do
  315.         {
  316.             history_line = (history_line - 1) & 31;
  317.         } while (history_line != edit_line
  318.                 && !key_lines[history_line][1]);
  319.         if (history_line == edit_line)
  320.             history_line = (edit_line+1)&31;
  321.         strcpy(key_lines[edit_line], key_lines[history_line]);
  322.         key_linepos = strlen(key_lines[edit_line]);
  323.         return;
  324.     }
  325.  
  326.     if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ||
  327.          ( ( key == 'n' ) && keydown[K_CTRL] ) )
  328.     {
  329.         if (history_line == edit_line) return;
  330.         do
  331.         {
  332.             history_line = (history_line + 1) & 31;
  333.         }
  334.         while (history_line != edit_line
  335.             && !key_lines[history_line][1]);
  336.         if (history_line == edit_line)
  337.         {
  338.             key_lines[edit_line][0] = ']';
  339.             key_linepos = 1;
  340.         }
  341.         else
  342.         {
  343.             strcpy(key_lines[edit_line], key_lines[history_line]);
  344.             key_linepos = strlen(key_lines[edit_line]);
  345.         }
  346.         return;
  347.     }
  348.  
  349.     if (key == K_PGUP || key == K_KP_PGUP )
  350.     {
  351.         con.display -= 2;
  352.         return;
  353.     }
  354.  
  355.     if (key == K_PGDN || key == K_KP_PGDN ) 
  356.     {
  357.         con.display += 2;
  358.         if (con.display > con.current)
  359.             con.display = con.current;
  360.         return;
  361.     }
  362.  
  363.     if (key == K_HOME || key == K_KP_HOME )
  364.     {
  365.         con.display = con.current - con.totallines + 10;
  366.         return;
  367.     }
  368.  
  369.     if (key == K_END || key == K_KP_END )
  370.     {
  371.         con.display = con.current;
  372.         return;
  373.     }
  374.     
  375.     if (key < 32 || key > 127)
  376.         return;    // non printable
  377.         
  378.     if (key_linepos < MAXCMDLINE-1)
  379.     {
  380.         key_lines[edit_line][key_linepos] = key;
  381.         key_linepos++;
  382.         key_lines[edit_line][key_linepos] = 0;
  383.     }
  384.  
  385. }
  386.  
  387. //============================================================================
  388.  
  389. qboolean    chat_team;
  390. char        chat_buffer[MAXCMDLINE];
  391. int            chat_bufferlen = 0;
  392.  
  393. void Key_Message (int key)
  394. {
  395.  
  396.     if ( key == K_ENTER || key == K_KP_ENTER )
  397.     {
  398.         if (chat_team)
  399.             Cbuf_AddText ("say_team \"");
  400.         else
  401.             Cbuf_AddText ("say \"");
  402.         Cbuf_AddText(chat_buffer);
  403.         Cbuf_AddText("\"\n");
  404.  
  405.         cls.key_dest = key_game;
  406.         chat_bufferlen = 0;
  407.         chat_buffer[0] = 0;
  408.         return;
  409.     }
  410.  
  411.     if (key == K_ESCAPE)
  412.     {
  413.         cls.key_dest = key_game;
  414.         chat_bufferlen = 0;
  415.         chat_buffer[0] = 0;
  416.         return;
  417.     }
  418.  
  419.     if (key < 32 || key > 127)
  420.         return;    // non printable
  421.  
  422.     if (key == K_BACKSPACE)
  423.     {
  424.         if (chat_bufferlen)
  425.         {
  426.             chat_bufferlen--;
  427.             chat_buffer[chat_bufferlen] = 0;
  428.         }
  429.         return;
  430.     }
  431.  
  432.     if (chat_bufferlen == sizeof(chat_buffer)-1)
  433.         return; // all full
  434.  
  435.     chat_buffer[chat_bufferlen++] = key;
  436.     chat_buffer[chat_bufferlen] = 0;
  437. }
  438.  
  439. //============================================================================
  440.  
  441.  
  442. /*
  443. ===================
  444. Key_StringToKeynum
  445.  
  446. Returns a key number to be used to index keybindings[] by looking at
  447. the given string.  Single ascii characters return themselves, while
  448. the K_* names are matched up.
  449. ===================
  450. */
  451. int Key_StringToKeynum (char *str)
  452. {
  453.     keyname_t    *kn;
  454.     
  455.     if (!str || !str[0])
  456.         return -1;
  457.     if (!str[1])
  458.         return str[0];
  459.  
  460.     for (kn=keynames ; kn->name ; kn++)
  461.     {
  462.         if (!Q_strcasecmp(str,kn->name))
  463.             return kn->keynum;
  464.     }
  465.     return -1;
  466. }
  467.  
  468. /*
  469. ===================
  470. Key_KeynumToString
  471.  
  472. Returns a string (either a single ascii char, or a K_* name) for the
  473. given keynum.
  474. FIXME: handle quote special (general escape sequence?)
  475. ===================
  476. */
  477. char *Key_KeynumToString (int keynum)
  478. {
  479.     keyname_t    *kn;    
  480.     static    char    tinystr[2];
  481.     
  482.     if (keynum == -1)
  483.         return "<KEY NOT FOUND>";
  484.     if (keynum > 32 && keynum < 127)
  485.     {    // printable ascii
  486.         tinystr[0] = keynum;
  487.         tinystr[1] = 0;
  488.         return tinystr;
  489.     }
  490.     
  491.     for (kn=keynames ; kn->name ; kn++)
  492.         if (keynum == kn->keynum)
  493.             return kn->name;
  494.  
  495.     return "<UNKNOWN KEYNUM>";
  496. }
  497.  
  498.  
  499. /*
  500. ===================
  501. Key_SetBinding
  502. ===================
  503. */
  504. void Key_SetBinding (int keynum, char *binding)
  505. {
  506.     char    *new;
  507.     int        l;
  508.             
  509.     if (keynum == -1)
  510.         return;
  511.  
  512. // free old bindings
  513.     if (keybindings[keynum])
  514.     {
  515.         Z_Free (keybindings[keynum]);
  516.         keybindings[keynum] = NULL;
  517.     }
  518.             
  519. // allocate memory for new binding
  520.     l = strlen (binding);    
  521.     new = Z_Malloc (l+1);
  522.     strcpy (new, binding);
  523.     new[l] = 0;
  524.     keybindings[keynum] = new;    
  525. }
  526.  
  527. /*
  528. ===================
  529. Key_Unbind_f
  530. ===================
  531. */
  532. void Key_Unbind_f (void)
  533. {
  534.     int        b;
  535.  
  536.     if (Cmd_Argc() != 2)
  537.     {
  538.         Com_Printf ("unbind <key> : remove commands from a key\n");
  539.         return;
  540.     }
  541.     
  542.     b = Key_StringToKeynum (Cmd_Argv(1));
  543.     if (b==-1)
  544.     {
  545.         Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  546.         return;
  547.     }
  548.  
  549.     Key_SetBinding (b, "");
  550. }
  551.  
  552. void Key_Unbindall_f (void)
  553. {
  554.     int        i;
  555.     
  556.     for (i=0 ; i<256 ; i++)
  557.         if (keybindings[i])
  558.             Key_SetBinding (i, "");
  559. }
  560.  
  561.  
  562. /*
  563. ===================
  564. Key_Bind_f
  565. ===================
  566. */
  567. void Key_Bind_f (void)
  568. {
  569.     int            i, c, b;
  570.     char        cmd[1024];
  571.     
  572.     c = Cmd_Argc();
  573.  
  574.     if (c < 2)
  575.     {
  576.         Com_Printf ("bind <key> [command] : attach a command to a key\n");
  577.         return;
  578.     }
  579.     b = Key_StringToKeynum (Cmd_Argv(1));
  580.     if (b==-1)
  581.     {
  582.         Com_Printf ("\"%s\" isn't a valid key\n", Cmd_Argv(1));
  583.         return;
  584.     }
  585.  
  586.     if (c == 2)
  587.     {
  588.         if (keybindings[b])
  589.             Com_Printf ("\"%s\" = \"%s\"\n", Cmd_Argv(1), keybindings[b] );
  590.         else
  591.             Com_Printf ("\"%s\" is not bound\n", Cmd_Argv(1) );
  592.         return;
  593.     }
  594.     
  595. // copy the rest of the command line
  596.     cmd[0] = 0;        // start out with a null string
  597.     for (i=2 ; i< c ; i++)
  598.     {
  599.         strcat (cmd, Cmd_Argv(i));
  600.         if (i != (c-1))
  601.             strcat (cmd, " ");
  602.     }
  603.  
  604.     Key_SetBinding (b, cmd);
  605. }
  606.  
  607. /*
  608. ============
  609. Key_WriteBindings
  610.  
  611. Writes lines containing "bind key value"
  612. ============
  613. */
  614. void Key_WriteBindings (FILE *f)
  615. {
  616.     int        i;
  617.  
  618.     for (i=0 ; i<256 ; i++)
  619.         if (keybindings[i] && keybindings[i][0])
  620.             fprintf (f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
  621. }
  622.  
  623.  
  624. /*
  625. ============
  626. Key_Bindlist_f
  627.  
  628. ============
  629. */
  630. void Key_Bindlist_f (void)
  631. {
  632.     int        i;
  633.  
  634.     for (i=0 ; i<256 ; i++)
  635.         if (keybindings[i] && keybindings[i][0])
  636.             Com_Printf ("%s \"%s\"\n", Key_KeynumToString(i), keybindings[i]);
  637. }
  638.  
  639.  
  640. /*
  641. ===================
  642. Key_Init
  643. ===================
  644. */
  645. void Key_Init (void)
  646. {
  647.     int        i;
  648.  
  649.     for (i=0 ; i<32 ; i++)
  650.     {
  651.         key_lines[i][0] = ']';
  652.         key_lines[i][1] = 0;
  653.     }
  654.     key_linepos = 1;
  655.     
  656. //
  657. // init ascii characters in console mode
  658. //
  659.     for (i=32 ; i<128 ; i++)
  660.         consolekeys[i] = true;
  661.     consolekeys[K_ENTER] = true;
  662.     consolekeys[K_KP_ENTER] = true;
  663.     consolekeys[K_TAB] = true;
  664.     consolekeys[K_LEFTARROW] = true;
  665.     consolekeys[K_KP_LEFTARROW] = true;
  666.     consolekeys[K_RIGHTARROW] = true;
  667.     consolekeys[K_KP_RIGHTARROW] = true;
  668.     consolekeys[K_UPARROW] = true;
  669.     consolekeys[K_KP_UPARROW] = true;
  670.     consolekeys[K_DOWNARROW] = true;
  671.     consolekeys[K_KP_DOWNARROW] = true;
  672.     consolekeys[K_BACKSPACE] = true;
  673.     consolekeys[K_HOME] = true;
  674.     consolekeys[K_KP_HOME] = true;
  675.     consolekeys[K_END] = true;
  676.     consolekeys[K_KP_END] = true;
  677.     consolekeys[K_PGUP] = true;
  678.     consolekeys[K_KP_PGUP] = true;
  679.     consolekeys[K_PGDN] = true;
  680.     consolekeys[K_KP_PGDN] = true;
  681.     consolekeys[K_SHIFT] = true;
  682.     consolekeys[K_INS] = true;
  683.     consolekeys[K_KP_INS] = true;
  684.     consolekeys[K_KP_DEL] = true;
  685.     consolekeys[K_KP_SLASH] = true;
  686.     consolekeys[K_KP_PLUS] = true;
  687.     consolekeys[K_KP_MINUS] = true;
  688.     consolekeys[K_KP_5] = true;
  689.  
  690.     consolekeys['`'] = false;
  691.     consolekeys['~'] = false;
  692.  
  693.     for (i=0 ; i<256 ; i++)
  694.         keyshift[i] = i;
  695.     for (i='a' ; i<='z' ; i++)
  696.         keyshift[i] = i - 'a' + 'A';
  697.     keyshift['1'] = '!';
  698.     keyshift['2'] = '@';
  699.     keyshift['3'] = '#';
  700.     keyshift['4'] = '$';
  701.     keyshift['5'] = '%';
  702.     keyshift['6'] = '^';
  703.     keyshift['7'] = '&';
  704.     keyshift['8'] = '*';
  705.     keyshift['9'] = '(';
  706.     keyshift['0'] = ')';
  707.     keyshift['-'] = '_';
  708.     keyshift['='] = '+';
  709.     keyshift[','] = '<';
  710.     keyshift['.'] = '>';
  711.     keyshift['/'] = '?';
  712.     keyshift[';'] = ':';
  713.     keyshift['\''] = '"';
  714.     keyshift['['] = '{';
  715.     keyshift[']'] = '}';
  716.     keyshift['`'] = '~';
  717.     keyshift['\\'] = '|';
  718.  
  719.     menubound[K_ESCAPE] = true;
  720.     for (i=0 ; i<12 ; i++)
  721.         menubound[K_F1+i] = true;
  722.  
  723. //
  724. // register our functions
  725. //
  726.     Cmd_AddCommand ("bind",Key_Bind_f);
  727.     Cmd_AddCommand ("unbind",Key_Unbind_f);
  728.     Cmd_AddCommand ("unbindall",Key_Unbindall_f);
  729.     Cmd_AddCommand ("bindlist",Key_Bindlist_f);
  730. }
  731.  
  732. /*
  733. ===================
  734. Key_Event
  735.  
  736. Called by the system between frames for both key up and key down events
  737. Should NOT be called during an interrupt!
  738. ===================
  739. */
  740. void Key_Event (int key, qboolean down, unsigned time)
  741. {
  742.     char    *kb;
  743.     char    cmd[1024];
  744.  
  745.     // hack for modal presses
  746.     if (key_waiting == -1)
  747.     {
  748.         if (down)
  749.             key_waiting = key;
  750.         return;
  751.     }
  752.  
  753.     // update auto-repeat status
  754.     if (down)
  755.     {
  756.         key_repeats[key]++;
  757.         if (key != K_BACKSPACE 
  758.             && key != K_PAUSE 
  759.             && key != K_PGUP 
  760.             && key != K_KP_PGUP 
  761.             && key != K_PGDN
  762.             && key != K_KP_PGDN
  763.             && key_repeats[key] > 1)
  764.             return;    // ignore most autorepeats
  765.             
  766.         if (key >= 200 && !keybindings[key])
  767.             Com_Printf ("%s is unbound, hit F4 to set.\n", Key_KeynumToString (key) );
  768.     }
  769.     else
  770.     {
  771.         key_repeats[key] = 0;
  772.     }
  773.  
  774.     if (key == K_SHIFT)
  775.         shift_down = down;
  776.  
  777.     // console key is hardcoded, so the user can never unbind it
  778.     if (key == '`' || key == '~')
  779.     {
  780.         if (!down)
  781.             return;
  782.         Con_ToggleConsole_f ();
  783.         return;
  784.     }
  785.  
  786.     // any key during the attract mode will bring up the menu
  787.     if (cl.attractloop && cls.key_dest != key_menu &&
  788.         !(key >= K_F1 && key <= K_F12))
  789.         key = K_ESCAPE;
  790.  
  791.     // menu key is hardcoded, so the user can never unbind it
  792.     if (key == K_ESCAPE)
  793.     {
  794.         if (!down)
  795.             return;
  796.  
  797.         if (cl.frame.playerstate.stats[STAT_LAYOUTS] && cls.key_dest == key_game)
  798.         {    // put away help computer / inventory
  799.             Cbuf_AddText ("cmd putaway\n");
  800.             return;
  801.         }
  802.         switch (cls.key_dest)
  803.         {
  804.         case key_message:
  805.             Key_Message (key);
  806.             break;
  807.         case key_menu:
  808.             M_Keydown (key);
  809.             break;
  810.         case key_game:
  811.         case key_console:
  812.             M_Menu_Main_f ();
  813.             break;
  814.         default:
  815.             Com_Error (ERR_FATAL, "Bad cls.key_dest");
  816.         }
  817.         return;
  818.     }
  819.  
  820.     // track if any key is down for BUTTON_ANY
  821.     keydown[key] = down;
  822.     if (down)
  823.     {
  824.         if (key_repeats[key] == 1)
  825.             anykeydown++;
  826.     }
  827.     else
  828.     {
  829.         anykeydown--;
  830.         if (anykeydown < 0)
  831.             anykeydown = 0;
  832.     }
  833.  
  834. //
  835. // key up events only generate commands if the game key binding is
  836. // a button command (leading + sign).  These will occur even in console mode,
  837. // to keep the character from continuing an action started before a console
  838. // switch.  Button commands include the kenum as a parameter, so multiple
  839. // downs can be matched with ups
  840. //
  841.     if (!down)
  842.     {
  843.         kb = keybindings[key];
  844.         if (kb && kb[0] == '+')
  845.         {
  846.             Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
  847.             Cbuf_AddText (cmd);
  848.         }
  849.         if (keyshift[key] != key)
  850.         {
  851.             kb = keybindings[keyshift[key]];
  852.             if (kb && kb[0] == '+')
  853.             {
  854.                 Com_sprintf (cmd, sizeof(cmd), "-%s %i %i\n", kb+1, key, time);
  855.                 Cbuf_AddText (cmd);
  856.             }
  857.         }
  858.         return;
  859.     }
  860.  
  861. //
  862. // if not a consolekey, send to the interpreter no matter what mode is
  863. //
  864.     if ( (cls.key_dest == key_menu && menubound[key])
  865.     || (cls.key_dest == key_console && !consolekeys[key])
  866.     || (cls.key_dest == key_game && ( cls.state == ca_active || !consolekeys[key] ) ) )
  867.     {
  868.         kb = keybindings[key];
  869.         if (kb)
  870.         {
  871.             if (kb[0] == '+')
  872.             {    // button commands add keynum and time as a parm
  873.                 Com_sprintf (cmd, sizeof(cmd), "%s %i %i\n", kb, key, time);
  874.                 Cbuf_AddText (cmd);
  875.             }
  876.             else
  877.             {
  878.                 Cbuf_AddText (kb);
  879.                 Cbuf_AddText ("\n");
  880.             }
  881.         }
  882.         return;
  883.     }
  884.  
  885.     if (!down)
  886.         return;        // other systems only care about key down events
  887.  
  888.     if (shift_down)
  889.         key = keyshift[key];
  890.  
  891.     switch (cls.key_dest)
  892.     {
  893.     case key_message:
  894.         Key_Message (key);
  895.         break;
  896.     case key_menu:
  897.         M_Keydown (key);
  898.         break;
  899.  
  900.     case key_game:
  901.     case key_console:
  902.         Key_Console (key);
  903.         break;
  904.     default:
  905.         Com_Error (ERR_FATAL, "Bad cls.key_dest");
  906.     }
  907. }
  908.  
  909. /*
  910. ===================
  911. Key_ClearStates
  912. ===================
  913. */
  914. void Key_ClearStates (void)
  915. {
  916.     int        i;
  917.  
  918.     anykeydown = false;
  919.  
  920.     for (i=0 ; i<256 ; i++)
  921.     {
  922.         if ( keydown[i] || key_repeats[i] )
  923.             Key_Event( i, false, 0 );
  924.         keydown[i] = 0;
  925.         key_repeats[i] = 0;
  926.     }
  927. }
  928.  
  929.  
  930. /*
  931. ===================
  932. Key_GetKey
  933. ===================
  934. */
  935. int Key_GetKey (void)
  936. {
  937.     key_waiting = -1;
  938.  
  939.     while (key_waiting == -1)
  940.         Sys_SendKeyEvents ();
  941.  
  942.     return key_waiting;
  943. }
  944.  
  945.